package io.github.echarts.model.geometry;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 表示填充样式
 * 包括颜色、透明度、渐变等属性
 */
public class FillStyle {
    
    /**
     * 渐变类型枚举
     */
    public enum GradientType {
        /**
         * 线性渐变
         */
        LINEAR,
        
        /**
         * 径向渐变
         */
        RADIAL
    }
    
    /**
     * 渐变停止点类
     * 表示渐变中的颜色点
     */
    public static class GradientStop {
        private final double offset;
        private final Color color;
        
        /**
         * 创建渐变停止点
         * 
         * @param offset 偏移量（0.0-1.0）
         * @param color 颜色
         */
        public GradientStop(double offset, Color color) {
            this.offset = Math.max(0.0, Math.min(1.0, offset));
            this.color = color != null ? color : Color.BLACK;
        }
        
        /**
         * 获取偏移量
         * 
         * @return 偏移量（0.0-1.0）
         */
        public double getOffset() {
            return offset;
        }
        
        /**
         * 获取颜色
         * 
         * @return 颜色
         */
        public Color getColor() {
            return color;
        }
        
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            
            GradientStop that = (GradientStop) o;
            
            if (Double.compare(that.offset, offset) != 0) return false;
            return Objects.equals(color, that.color);
        }
        
        @Override
        public int hashCode() {
            int result;
            long temp;
            temp = Double.doubleToLongBits(offset);
            result = (int) (temp ^ (temp >>> 32));
            result = 31 * result + (color != null ? color.hashCode() : 0);
            return result;
        }
        
        @Override
        public String toString() {
            return String.format("GradientStop{offset=%.2f, color=%s}", offset, color);
        }
    }
    
    /**
     * 默认填充颜色
     */
    public static final Color DEFAULT_COLOR = Color.BLACK;
    
    /**
     * 默认不透明度
     */
    public static final double DEFAULT_OPACITY = 1.0;
    
    /**
     * 填充颜色
     */
    private final Color color;
    
    /**
     * 不透明度，0.0-1.0，0.0表示完全透明，1.0表示完全不透明
     */
    private final double opacity;
    
    /**
     * 是否使用渐变
     */
    private final boolean gradient;
    
    /**
     * 渐变类型
     */
    private final GradientType gradientType;
    
    /**
     * 渐变起点
     */
    private final Point gradientStart;
    
    /**
     * 渐变终点
     */
    private final Point gradientEnd;
    
    /**
     * 渐变半径（仅用于径向渐变）
     */
    private final double gradientRadius;
    
    /**
     * 渐变停止点列表
     */
    private final List<GradientStop> gradientStops;
    
    /**
     * 创建默认填充样式（黑色填充，不透明）
     */
    public FillStyle() {
        this(DEFAULT_COLOR);
    }
    
    /**
     * 创建填充样式，使用指定颜色和默认不透明度
     * 
     * @param color 填充颜色
     */
    public FillStyle(Color color) {
        this(color, DEFAULT_OPACITY);
    }
    
    /**
     * 创建填充样式，使用指定颜色和不透明度
     * 
     * @param color 填充颜色
     * @param opacity 不透明度
     */
    public FillStyle(Color color, double opacity) {
        this.color = color != null ? color : DEFAULT_COLOR;
        this.opacity = Math.max(0.0, Math.min(1.0, opacity));
        this.gradient = false;
        this.gradientType = null;
        this.gradientStart = null;
        this.gradientEnd = null;
        this.gradientRadius = 0.0;
        this.gradientStops = null;
    }
    
    /**
     * 创建线性渐变填充样式
     * 
     * @param start 渐变起点
     * @param end 渐变终点
     * @param stops 渐变停止点列表
     */
    public FillStyle(Point start, Point end, List<GradientStop> stops) {
        this.color = null;
        this.opacity = DEFAULT_OPACITY;
        this.gradient = true;
        this.gradientType = GradientType.LINEAR;
        this.gradientStart = start != null ? start : new Point(0, 0);
        this.gradientEnd = end != null ? end : new Point(1, 0);
        this.gradientRadius = 0.0;
        
        if (stops != null && !stops.isEmpty()) {
            // 按偏移量排序
            List<GradientStop> sortedStops = new ArrayList<>(stops);
            Collections.sort(sortedStops, (s1, s2) -> Double.compare(s1.getOffset(), s2.getOffset()));
            this.gradientStops = Collections.unmodifiableList(sortedStops);
        } else {
            // 默认创建黑白渐变
            List<GradientStop> defaultStops = new ArrayList<>();
            defaultStops.add(new GradientStop(0.0, Color.BLACK));
            defaultStops.add(new GradientStop(1.0, Color.WHITE));
            this.gradientStops = Collections.unmodifiableList(defaultStops);
        }
    }
    
    /**
     * 创建径向渐变填充样式
     * 
     * @param center 渐变中心点
     * @param radius 渐变半径
     * @param stops 渐变停止点列表
     */
    public FillStyle(Point center, double radius, List<GradientStop> stops) {
        this.color = null;
        this.opacity = DEFAULT_OPACITY;
        this.gradient = true;
        this.gradientType = GradientType.RADIAL;
        this.gradientStart = center != null ? center : new Point(0, 0);
        this.gradientEnd = null;
        this.gradientRadius = Math.max(0.0, radius);
        
        if (stops != null && !stops.isEmpty()) {
            // 按偏移量排序
            List<GradientStop> sortedStops = new ArrayList<>(stops);
            Collections.sort(sortedStops, (s1, s2) -> Double.compare(s1.getOffset(), s2.getOffset()));
            this.gradientStops = Collections.unmodifiableList(sortedStops);
        } else {
            // 默认创建黑白渐变
            List<GradientStop> defaultStops = new ArrayList<>();
            defaultStops.add(new GradientStop(0.0, Color.BLACK));
            defaultStops.add(new GradientStop(1.0, Color.WHITE));
            this.gradientStops = Collections.unmodifiableList(defaultStops);
        }
    }
    
    /**
     * 获取填充颜色
     * 
     * @return 填充颜色，如果是渐变填充则返回null
     */
    public Color getColor() {
        return color;
    }
    
    /**
     * 获取不透明度
     * 
     * @return 不透明度
     */
    public double getOpacity() {
        return opacity;
    }
    
    /**
     * 判断是否使用渐变填充
     * 
     * @return 是否使用渐变
     */
    public boolean isGradient() {
        return gradient;
    }
    
    /**
     * 获取渐变类型
     * 
     * @return 渐变类型，如果不是渐变填充则返回null
     */
    public GradientType getGradientType() {
        return gradientType;
    }
    
    /**
     * 获取渐变起点
     * 
     * @return 渐变起点或中心点，如果不是渐变填充则返回null
     */
    public Point getGradientStart() {
        return gradientStart;
    }
    
    /**
     * 获取渐变终点
     * 
     * @return 渐变终点，如果不是线性渐变填充则返回null
     */
    public Point getGradientEnd() {
        return gradientEnd;
    }
    
    /**
     * 获取渐变半径
     * 
     * @return 渐变半径，如果不是径向渐变填充则返回0.0
     */
    public double getGradientRadius() {
        return gradientRadius;
    }
    
    /**
     * 获取渐变停止点列表
     * 
     * @return 渐变停止点列表，如果不是渐变填充则返回null
     */
    public List<GradientStop> getGradientStops() {
        return gradientStops;
    }
    
    /**
     * 创建一个新的FillStyle，使用新的颜色
     * 
     * @param color 新的填充颜色
     * @return 新的FillStyle对象
     */
    public FillStyle withColor(Color color) {
        return new FillStyle(color, this.opacity);
    }
    
    /**
     * 创建一个新的FillStyle，使用新的不透明度
     * 
     * @param opacity 新的不透明度
     * @return 新的FillStyle对象
     */
    public FillStyle withOpacity(double opacity) {
        if (this.gradient) {
            if (this.gradientType == GradientType.LINEAR) {
                // 创建调整透明度的停止点
                List<GradientStop> newStops = new ArrayList<>();
                for (GradientStop stop : this.gradientStops) {
                    newStops.add(new GradientStop(stop.getOffset(), 
                            stop.getColor().withAlpha(stop.getColor().getAlpha() * opacity)));
                }
                return new FillStyle(this.gradientStart, this.gradientEnd, newStops);
            } else {
                // 径向渐变
                List<GradientStop> newStops = new ArrayList<>();
                for (GradientStop stop : this.gradientStops) {
                    newStops.add(new GradientStop(stop.getOffset(), 
                            stop.getColor().withAlpha(stop.getColor().getAlpha() * opacity)));
                }
                return new FillStyle(this.gradientStart, this.gradientRadius, newStops);
            }
        } else {
            return new FillStyle(this.color, opacity);
        }
    }
    
    /**
     * 创建一个新的线性渐变FillStyle，使用两种颜色
     * 
     * @param startColor 起始颜色
     * @param endColor 结束颜色
     * @param start 渐变起点
     * @param end 渐变终点
     * @return 新的FillStyle对象
     */
    public static FillStyle linearGradient(Color startColor, Color endColor, Point start, Point end) {
        List<GradientStop> stops = new ArrayList<>();
        stops.add(new GradientStop(0.0, startColor != null ? startColor : Color.BLACK));
        stops.add(new GradientStop(1.0, endColor != null ? endColor : Color.WHITE));
        return new FillStyle(start, end, stops);
    }
    
    /**
     * 创建一个新的径向渐变FillStyle，使用两种颜色
     * 
     * @param centerColor 中心颜色
     * @param outerColor 外部颜色
     * @param center 中心点
     * @param radius 半径
     * @return 新的FillStyle对象
     */
    public static FillStyle radialGradient(Color centerColor, Color outerColor, Point center, double radius) {
        List<GradientStop> stops = new ArrayList<>();
        stops.add(new GradientStop(0.0, centerColor != null ? centerColor : Color.BLACK));
        stops.add(new GradientStop(1.0, outerColor != null ? outerColor : Color.WHITE));
        return new FillStyle(center, radius, stops);
    }
    
    /**
     * 获取CSS样式字符串表示
     * 
     * @return CSS样式字符串
     */
    public String toCssString() {
        StringBuilder css = new StringBuilder();
        
        if (gradient) {
            if (gradientType == GradientType.LINEAR) {
                // 线性渐变
                double x1 = gradientStart.getX();
                double y1 = gradientStart.getY();
                double x2 = gradientEnd.getX();
                double y2 = gradientEnd.getY();
                
                css.append("background: linear-gradient(");
                // 计算角度 (CSS中角度是顺时针，数学中是逆时针)
                double angle = (Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI + 90) % 360;
                css.append(angle).append("deg");
                
                // 添加颜色停止点
                for (GradientStop stop : gradientStops) {
                    css.append(", ").append(stop.getColor().toCssString());
                    css.append(" ").append(Math.round(stop.getOffset() * 100)).append("%");
                }
                
                css.append(");");
            } else {
                // 径向渐变
                css.append("background: radial-gradient(circle at ");
                css.append(Math.round(gradientStart.getX())).append("px ");
                css.append(Math.round(gradientStart.getY())).append("px");
                
                // 添加颜色停止点
                for (GradientStop stop : gradientStops) {
                    css.append(", ").append(stop.getColor().toCssString());
                    css.append(" ").append(Math.round(stop.getOffset() * 100)).append("%");
                }
                
                css.append(");");
            }
        } else {
            // 纯色填充
            if (opacity < 1.0) {
                css.append("background-color: ").append(color.toCssString()).append(";");
            } else {
                css.append("background-color: ").append(color.toHexString(false)).append(";");
            }
        }
        
        return css.toString();
    }
    
    /**
     * 获取SVG填充属性表示
     * 
     * @return SVG属性字符串
     */
    public String toSvgAttributes() {
        StringBuilder attrs = new StringBuilder();
        
        if (gradient) {
            String gradientId = "gradient_" + Math.abs(hashCode());
            attrs.append("fill=\"url(#").append(gradientId).append(")\" ");
            
            // 透明度
            if (opacity < 1.0) {
                attrs.append("fill-opacity=\"").append(opacity).append("\" ");
            }
            
            // 注意：渐变定义应该在SVG的defs部分，这里只返回引用
            // 完整实现需要在渲染时处理渐变的定义
        } else {
            // 纯色填充
            attrs.append("fill=\"").append(color.toHexString(false)).append("\" ");
            
            // 透明度
            if (opacity < 1.0) {
                attrs.append("fill-opacity=\"").append(opacity).append("\" ");
            }
        }
        
        return attrs.toString().trim();
    }
    
    /**
     * 获取SVG渐变定义
     * 
     * @return SVG渐变定义字符串，如果不是渐变填充则返回空字符串
     */
    public String getSvgGradientDefinition() {
        if (!gradient) {
            return "";
        }
        
        StringBuilder def = new StringBuilder();
        String gradientId = "gradient_" + Math.abs(hashCode());
        
        if (gradientType == GradientType.LINEAR) {
            // 线性渐变
            def.append("<linearGradient id=\"").append(gradientId).append("\" ");
            def.append("x1=\"").append(gradientStart.getX()).append("\" ");
            def.append("y1=\"").append(gradientStart.getY()).append("\" ");
            def.append("x2=\"").append(gradientEnd.getX()).append("\" ");
            def.append("y2=\"").append(gradientEnd.getY()).append("\">");
            
            // 添加渐变停止点
            for (GradientStop stop : gradientStops) {
                def.append("<stop offset=\"").append(stop.getOffset() * 100).append("%\" ");
                def.append("stop-color=\"").append(stop.getColor().toHexString(false)).append("\" ");
                if (stop.getColor().getAlpha() < 1.0) {
                    def.append("stop-opacity=\"").append(stop.getColor().getAlpha()).append("\" ");
                }
                def.append("/>");
            }
            
            def.append("</linearGradient>");
        } else {
            // 径向渐变
            def.append("<radialGradient id=\"").append(gradientId).append("\" ");
            def.append("cx=\"").append(gradientStart.getX()).append("\" ");
            def.append("cy=\"").append(gradientStart.getY()).append("\" ");
            def.append("r=\"").append(gradientRadius).append("\" ");
            def.append("gradientUnits=\"userSpaceOnUse\">");
            
            // 添加渐变停止点
            for (GradientStop stop : gradientStops) {
                def.append("<stop offset=\"").append(stop.getOffset() * 100).append("%\" ");
                def.append("stop-color=\"").append(stop.getColor().toHexString(false)).append("\" ");
                if (stop.getColor().getAlpha() < 1.0) {
                    def.append("stop-opacity=\"").append(stop.getColor().getAlpha()).append("\" ");
                }
                def.append("/>");
            }
            
            def.append("</radialGradient>");
        }
        
        return def.toString();
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        FillStyle fillStyle = (FillStyle) o;
        
        if (Double.compare(fillStyle.opacity, opacity) != 0) return false;
        if (gradient != fillStyle.gradient) return false;
        if (Double.compare(fillStyle.gradientRadius, gradientRadius) != 0) return false;
        if (!Objects.equals(color, fillStyle.color)) return false;
        if (gradientType != fillStyle.gradientType) return false;
        if (!Objects.equals(gradientStart, fillStyle.gradientStart)) return false;
        if (!Objects.equals(gradientEnd, fillStyle.gradientEnd)) return false;
        return Objects.equals(gradientStops, fillStyle.gradientStops);
    }
    
    @Override
    public int hashCode() {
        int result;
        long temp;
        result = color != null ? color.hashCode() : 0;
        temp = Double.doubleToLongBits(opacity);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (gradient ? 1 : 0);
        result = 31 * result + (gradientType != null ? gradientType.hashCode() : 0);
        result = 31 * result + (gradientStart != null ? gradientStart.hashCode() : 0);
        result = 31 * result + (gradientEnd != null ? gradientEnd.hashCode() : 0);
        temp = Double.doubleToLongBits(gradientRadius);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        result = 31 * result + (gradientStops != null ? gradientStops.hashCode() : 0);
        return result;
    }
    
    @Override
    public String toString() {
        if (gradient) {
            if (gradientType == GradientType.LINEAR) {
                return "FillStyle{linearGradient, start=" + gradientStart + 
                        ", end=" + gradientEnd + ", stops=" + gradientStops + '}';
            } else {
                return "FillStyle{radialGradient, center=" + gradientStart + 
                        ", radius=" + gradientRadius + ", stops=" + gradientStops + '}';
            }
        } else {
            if (opacity < 1.0) {
                return "FillStyle{color=" + color + ", opacity=" + opacity + '}';
            } else {
                return "FillStyle{color=" + color + '}';
            }
        }
    }
} 